package handler

import (
	"context"
	"fmt"
	"github.com/fasthttp/websocket"
	"github.com/valyala/fasthttp"
	"net/http"
	"strings"
	"sync/atomic"

	"kop/framework/broker"
	ws "kop/libs/websocket"
	"kop/modules/api/cron"
	"kop/modules/api/models"
	"kop/pb"
	"kop/pb/service"
	"kop/util/log"

	guildC "kop/modules/guild/client"
	moneyC "kop/modules/money/client"
	roleC "kop/modules/role/client"
)

var upgrade = websocket.FastHTTPUpgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *fasthttp.RequestCtx) bool {

		return true
	},
}

func wsHandler(ctx *fasthttp.RequestCtx) {

	// 先读令牌
	var tokenS = strings.Replace(string(ctx.Path()), "/ws/", "", -1)

	var user, err = models.GetUser(tokenS)
	if err != nil {
		// 未认证
		ctx.SetStatusCode(http.StatusUnauthorized)
		_, _ = ctx.WriteString("ws handler token error")
		return
	}

	var roleID = user.RoleID

	_ = upgrade.Upgrade(ctx, func(conn *websocket.Conn) {

		var c = ws.Conn{Conn: conn}

		c.Init()
		//c.SetDeadline(60)
		defer c.Close()

		go read(&c, roleID, user.ServerID)

		// 订阅全服消息
		var subscriber, err = broker.Subscribe("go.micro.topic.server0", c.Chan)
		if err != nil {
			//log.Error("订阅全服消息Error " + err.Error())
		}
		defer subscriber.Unsubscribe()

		// 订阅本服消息
		subscriber, err = broker.Subscribe(fmt.Sprintf("go.micro.topic.server%d", user.ServerID), c.Chan)
		if err != nil {
			//log.Error("订阅本服消息Error " + err.Error())
		}
		defer subscriber.Unsubscribe()

		defer c.Subscribers.Unsubscribe()

		if user.GuildID > 0 {

			if guild, err := guildC.MyGuild(roleID, user.ServerID, user.GuildID); err == nil {
				if guild != nil {
					// 订阅公会消息
					_, _ = guildC.Online(roleID, user.ServerID, user.GuildID)

					_ = c.Subscribers.Subscribe(fmt.Sprintf("go.micro.topic.guild%d", user.GuildID), c.Chan)
					//subscribers = append(subscribers, subscriber)
				} else {
					user.GuildID = 0
					_ = models.SaveUser(tokenS, &user)
				}
			}
		}

		subscriber, err = broker.SubRoleChannel(tokenS, &user, c.Chan, &c.Subscribers)
		if err != nil {
			//log.Error("订阅玩家消息Error " + err.Error())
		}

		// 在线人数
		atomic.AddInt32(&cron.OnlineNum, 1)

		var roleRequest = service.RoleRequest{RoleID: roleID}
		go roleC.RoleService.Online(context.Background(), &roleRequest)

		defer func() {

			atomic.AddInt32(&cron.OnlineNum, -1)

			_ = subscriber.Unsubscribe() // 退订个人消息

			_, _ = guildC.Offline(roleID, user.ServerID, user.GuildID)
			_, _ = moneyC.MoneyService.Offline(context.Background(), &roleRequest)
			_, _ = roleC.RoleService.Offline(context.Background(), &roleRequest)
		}()

		c.WhatEver()
		//log.Info("RoleID:[%d] Disconnect", roleID)
	})
}

func read(c *ws.Conn, roleID, serverID int32) {

	for {

		var _, data, err = c.Conn.ReadMessage()
		if err != nil {

			if websocket.IsCloseError(err, websocket.CloseGoingAway) {

			} else if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {

			} else {
				log.Error(err.Error())
			}

			break
		}

		if len(data) > 0 {
			switch data[0] {
			case byte(pb.WsCode_SubWorldBoss):
				_ = c.Subscribers.Subscribe(fmt.Sprintf("go.micro.topic.boss.%d", serverID), c.Chan)
				log.Info("[%d] in boss interface", roleID)

			case byte(pb.WsCode_UnSubWorldBoss):
				c.Subscribers.UnContains("go.micro.topic.boss")
				log.Info("[%d] quit boss", roleID)

			case byte(pb.WsCode_SubTreasure):
				_ = c.Subscribers.Subscribe(fmt.Sprintf("go.micro.topic.treas.%d", serverID), c.Chan)
				log.Info("[%d] in treas interface", roleID)

			case byte(pb.WsCode_UnSubTreasure):
				c.Subscribers.UnContains("go.micro.topic.treas")
				log.Info("[%d] quit treas", roleID)
			}
		}
	}

	c.Done <- true
}
